using System;
using System.Drawing;
using System.Windows.Forms;
using System.ComponentModel;

using needle.UI.Controls.Flat.Resources;
using needle.UI.Controls.Flat.Resources.Keys;
using needle.UI.Controls.Flat.Windows.Forms;
using needle.UI.Controls.Flat.Windows.Forms.Helpers;
using needle.UI.Controls.Flat.Windows.Forms.Collections;

using needle.UI.Controls.Flat.Utilities;
using needle.UI.Controls.Flat.Utilities.Win32;

namespace needle.UI.Controls.Flat.Windows.Docking
{
	[ToolboxItem(false)]
    public class AutoHidePanel : System.Windows.Forms.Panel, IMessageFilter
	{
		#region Nested types

		[ToolboxItem(false)]
        protected class AutoHostPanel : System.Windows.Forms.Panel, global::needle.UI.Controls.Flat.Windows.Forms.IResizeSource
		{
            protected Edge mborderEdge;
            protected needle.UI.Controls.Flat.Windows.Forms.ResizeAutoBar mresizeAutoBar;
            protected AutoHidePanel mautoHidePanel;
            protected DockingManager mmanager;

			public AutoHostPanel(DockingManager manager, AutoHidePanel autoHidePanel, Edge borderEdge)
			{
                mmanager = manager;
                mautoHidePanel = autoHidePanel;
                mborderEdge = borderEdge;
				
				Direction direction;
				
				if ((borderEdge == Edge.Left) || (borderEdge == Edge.Right))
				    direction = Direction.Horizontal;
				else
				    direction = Direction.Vertical;
				
				mresizeAutoBar = new needle.UI.Controls.Flat.Windows.Forms.ResizeAutoBar(direction, this);
				
				Controls.Add(mresizeAutoBar);
				
				switch(mborderEdge)
				{
				    case Edge.Left:
				        mresizeAutoBar.Dock = DockStyle.Left;
				        break;
                    case Edge.Right:
                        mresizeAutoBar.Dock = DockStyle.Right;
                        break;
                    case Edge.Top:
                        mresizeAutoBar.Dock = DockStyle.Top;
                        break;
                    case Edge.Bottom:
                        mresizeAutoBar.Dock = DockStyle.Bottom;
                        break;
                }
			}

            public Size ResizeBarSize()
            {
                return mresizeAutoBar.Size;
            }

            public int MinimumWidth 
            { 
                get { return mresizeAutoBar.Width * 5; }
            }
		
            public int MinimumHeight
            { 
                get { return mresizeAutoBar.Height * 6; } 
            }

            public Color ResizeBarColor
            {
                get { return mmanager.ResizeBarColor; }
            }
            
            public int ResizeBarVector
            {
                get { return mmanager.ResizeBarVector; }
            }
            
            public Color BackgroundColor
            {
                get { return mmanager.BackColor; }
            }

            public bool CanResize(global::needle.UI.Controls.Flat.Windows.Forms.ResizeBar bar)
            {
                return true;
            }

            //public VisualStyle Style {
            //    get { return mmanager.Style; }
            //}

            public bool StartResizeOperation(global::needle.UI.Controls.Flat.Windows.Forms.ResizeBar bar, ref Rectangle screenBoundary)
            {
                mautoHidePanel.SetFocusToWct();    
            
                screenBoundary = this.Parent.RectangleToScreen(mmanager.InnerResizeRectangle(this));

                Rectangle panelBoundary = RectangleToScreen(this.ClientRectangle);

                int minHeight = this.MinimumHeight;
                int minWidth = this.MinimumWidth;

                switch(mborderEdge)
                {
                    case Edge.Bottom:
                        {
                            int diff = panelBoundary.Top - screenBoundary.Top + minHeight;
                            screenBoundary.Y += diff;
                            screenBoundary.Height -= diff;					

                            int innerMinimumWidth = mmanager.InnerMinimum.Height;
                            screenBoundary.Height -= innerMinimumWidth;
                        }
                        break;
                    case Edge.Top:
                        {
                            int diff = panelBoundary.Bottom - screenBoundary.Bottom - minHeight;
                            screenBoundary.Height += diff;					

                            int innerMinimumWidth = mmanager.InnerMinimum.Height;
                            screenBoundary.Y += innerMinimumWidth;
                            screenBoundary.Height -= innerMinimumWidth;
                        }
                        break;
                    case Edge.Right:
                        {
                            int diff = panelBoundary.Left - screenBoundary.Left + minWidth;
                            screenBoundary.X += diff;
                            screenBoundary.Width -= diff;					

                            int innerMinimumWidth = mmanager.InnerMinimum.Width;
                            screenBoundary.Width -=	innerMinimumWidth;
                        }
                        break;
                    case Edge.Left:
                        {
                            int diff = panelBoundary.Right - screenBoundary.Right - minWidth;
                            screenBoundary.Width += diff;

                            int innerMinimumWidth = mmanager.InnerMinimum.Width;
                            screenBoundary.X += innerMinimumWidth;
                            screenBoundary.Width -=	innerMinimumWidth;
                        }
                        break;
                }

                return true;
            }

            public void EndResizeOperation(global::needle.UI.Controls.Flat.Windows.Forms.ResizeBar bar, int delta)
            {
                switch(mborderEdge)
                {
                    case Edge.Right:
                        Controls[1].Width += delta;
                        this.Width += delta;
                        mautoHidePanel.UpdateContentSize(Controls[1].Width, true);
                        break;
                    case Edge.Left:
                        Controls[1].Width -= delta;
                        this.Width -= delta;
                        this.Left += delta;
                        mautoHidePanel.UpdateContentSize(Controls[1].Width, true);
                        break;
                    case Edge.Bottom:
                        Controls[1].Height += delta;
                        this.Height += delta;
                        mautoHidePanel.UpdateContentSize(Controls[1].Height, false);
                        break;
                    case Edge.Top:
                        Controls[1].Height -= delta;
                        this.Height -= delta;
                        this.Top += delta;
                        mautoHidePanel.UpdateContentSize(Controls[1].Height, false);
                        break;
                }
                
                mautoHidePanel.DefineRectangles();
            }

            public void PropogateNameValue(PropogateName name, object value)
            {
                switch(name)
                {
                    case PropogateName.BackColor:
                        this.BackColor = (Color)value;
                        Invalidate();
                        break;
                }

                mresizeAutoBar.PropogateNameValue(name, value);            
            }

			protected override void OnPaintBackground(PaintEventArgs e)
			{
			}

			protected override void OnPaint(PaintEventArgs e)
			{
			}
		}

		#endregion

	    protected static int mnum = 0;
        protected static int mslideSteps = 4;
        protected static int mslideInterval = 15;
        protected static int mdismissInterval = 1000;
	
	    protected int mnumber;
        protected bool mkilling;
        protected bool mdefaultColor;
        protected bool mdismissRunning;
        protected bool mslideRunning;
        protected bool mignoreDismiss;
        protected bool mslideOut;
        protected int mslideStep;
        protected Timer mslideTimer;
        protected Timer mdismissTimer;
        protected Rectangle mslideRect;
        protected Rectangle mrememberRect;
        protected DockingManager mmanager;
        protected AutoHostPanel mcurrentPanel;
        protected WindowContentTabbed mcurrentWct;
        
		#region Constructors

		public AutoHidePanel(DockingManager manager, DockStyle dockEdge)
		{
            mnumber = mnum++;
            mdefaultColor = true;
            mdismissRunning = false;
            mslideRunning = false;
            mignoreDismiss = false;
            mkilling = false;
            mmanager = manager;
            mcurrentWct = null;
            mcurrentPanel = null;
            mslideRect = new Rectangle();
            mrememberRect = new Rectangle();
            
            int vector = TabStub.TabStubVector(this.Font);
            
            this.Size = new Size(vector, vector);

			this.Dock = dockEdge;

			this.Hide();

            mmanager.Container.Resize += new EventHandler(OnContainerResized);

            Application.AddMessageFilter(this);
            
            CreateTimers();
        }

		#endregion

		#region Overrides

		protected override void OnSystemColorsChanged(EventArgs e)
		{
			if (mdefaultColor)
				Invalidate();
		}

		#endregion

		#region Virtuals

		protected void CreateTimers()
		{
			mslideTimer = new Timer();
			mslideTimer.Interval = mslideInterval;
			mslideTimer.Tick += new EventHandler(OnSlideTick);
            
			mdismissTimer = new Timer();
			mdismissTimer.Interval = mdismissInterval;
			mdismissTimer.Tick += new EventHandler(OnDismissTick);
		}

		protected void StartDismissTimer()
		{
			if (!mdismissRunning)
			{
				mdismissRunning = true;
				mdismissTimer.Start();
			}
		}

		#endregion

		#region Virtuals

		protected void StopDismissTimer()
		{
			mdismissRunning = false;
			mdismissTimer.Stop();
		}
        
		protected void StartSlideTimer()
		{
			if (!mslideRunning)
			{
				mslideStep = 0;
				mslideRunning = true;
				mslideTimer.Start();
			}
		}

		protected void StopSlideTimer()
		{
			mslideRunning = false;
			mslideTimer.Stop();
		}

		protected TabStub TabStubForContent(Content c)
		{
			foreach(TabStub ts in this.Controls)
			{
				foreach(needle.UI.Controls.Flat.Windows.Forms.TabPage page in ts.TabPages)
				{
					if (c.Title == (page.Tag as Content).Title)
						return ts;
				}
			}
            
			return null;
		}

		protected void RemoveDisplayedWindow()
		{
			if (mcurrentPanel != null)
			{
				MonitorPanel(false);

				ControlUtilities.Remove(mcurrentPanel.Controls, mcurrentWct);
				ControlUtilities.Remove(mmanager.Container.Controls, mcurrentPanel);
			}
            
			if (mcurrentWct != null)
			{            
				mcurrentWct.Width = mrememberRect.Width;
				mcurrentWct.Height = mrememberRect.Height;
			}
                        
			if (mcurrentPanel != null)
			{
				mcurrentPanel.Dispose();
				mcurrentPanel = null;
			}
		}

		protected void KillDisplayedWindow(WindowContentTabbed wct)
		{
			mkilling = true;
            
			StopDismissTimer();

			if (wct != null)
			{
				int count = wct.Contents.Count;
	            
				for(int index=0; index<count; index++)
				{
					wct.Contents.RemoveAt(0);
				}
	            
				RemoveDisplayedWindow();

				wct.Dispose();

				if (wct == mcurrentWct)
					mcurrentWct = null;
			}
            
			mkilling = false;
		}

		protected void UpdateContentSize(int newVector, bool isWidth)
		{
			if (mcurrentPanel != null)
			{
				if (mcurrentWct != null)
				{
					foreach(Content c in mcurrentWct.Contents)
					{
						Size s = c.AutoHideSize;
                        
						if (isWidth)
							s.Width = newVector;
						else
							s.Height = newVector;
                            
						c.AutoHideSize = s;
					}
				}
			}
		}

		protected void DefineRectangles()
		{
			mrememberRect = mcurrentWct.ClientRectangle;        

			mslideRect = mrememberRect;

			Rectangle availableSize = mmanager.InnerResizeRectangle(this);
            
			if (availableSize.Width < mslideRect.Width)
				mslideRect.Width = availableSize.Width;

			if (availableSize.Height < mslideRect.Height)
				mslideRect.Height = availableSize.Height;
		}

		protected void SetFocusToWct()
		{
			if (mcurrentPanel != null)
			{
				if (!mcurrentWct.ContainsFocus)
				{
					mcurrentWct.Focus();
					mcurrentWct.Refresh();
				}
			}
		}
        
		protected void OnPageClicked(object sender, TabStub.TabStubIndexEventArgs e)
		{
			mmanager.RemoveShowingAutoHideWindowsExcept(this);
            
			OnPageOver(sender, e);

			SetFocusToWct();
		}
        
		protected void OnPageOver(object sender, TabStub.TabStubIndexEventArgs e)
		{
			mmanager.RemoveShowingAutoHideWindowsExcept(this);
            
			StopDismissTimer();

			if (mcurrentWct != ((TabStub)sender).WindowContentTabbed)
			{
				if (mcurrentWct != null)
					RemoveDisplayedWindow();
			}
			else
			{
				if (e.PageIndex != mcurrentWct.TabControl.SelectedIndex)
				{
					if (mcurrentWct != null)
						RemoveDisplayedWindow();
				}            
				else
				{
					return;
				}
			}

			Edge borderEdge = Edge.None;

			switch(this.Dock)
			{
				case DockStyle.Left:
					borderEdge = Edge.Right;
					break;
				case DockStyle.Right:
					borderEdge = Edge.Left;
					break;
				case DockStyle.Top:
					borderEdge = Edge.Bottom;
					break;
				case DockStyle.Bottom:
					borderEdge = Edge.Top;
					break;
			}

			mcurrentPanel = new AutoHostPanel(mmanager, this, borderEdge);
            
			mcurrentPanel.Hide();                 
            
			mcurrentWct = ((TabStub)sender).WindowContentTabbed;

			mcurrentWct.TabControl.SelectedIndex = e.PageIndex;            
                
			mcurrentPanel.Controls.Add(mcurrentWct);

			mmanager.Container.Controls.Add(mcurrentPanel);
		    
			mmanager.Container.Controls.SetChildIndex(mcurrentPanel, 0);

			DefineRectangles();

			mcurrentWct.Width = mslideRect.Width;
			mcurrentWct.Height = mslideRect.Height;

			Size barSize = mcurrentPanel.ResizeBarSize();

			switch(this.Dock)
			{
				case DockStyle.Left:
					mcurrentPanel.Size = new Size(0, this.Height);
					mcurrentPanel.Location = new Point(this.Right, this.Top);
					mcurrentWct.Height = this.Height;
					break;
				case DockStyle.Right:
					mcurrentPanel.Size = new Size(0, this.Height);
					mcurrentPanel.Location = new Point(this.Left, this.Top);
					mcurrentWct.Height = this.Height;
					break;
				case DockStyle.Top:
					mcurrentPanel.Size = new Size(this.Width, 0);
					mcurrentPanel.Location = new Point(this.Left, this.Bottom);
					mcurrentWct.Width = this.Width;
					break;
				case DockStyle.Bottom:
					mcurrentPanel.Size = new Size(this.Width, 0);
					mcurrentPanel.Location = new Point(this.Left, this.Top);
					mcurrentWct.Width = this.Width;
					break;
			}

			mcurrentPanel.Show();
                
			MonitorPanel(true);

			mslideOut = true;
                
			StartSlideTimer();
		}
        
		protected void OnPagesLeave(object sender, EventArgs e)
		{
			if ((mcurrentPanel != null) && (mcurrentWct != null))
			{
				if (!mcurrentPanel.ContainsFocus)
					StartDismissTimer();
			}
		}

		protected void OnPageClose(object sender, EventArgs e)
		{
			foreach(TabStub ts in this.Controls)
			{
				if (ts.WindowContentTabbed == mcurrentWct)
				{
					ContentCollection cc = new ContentCollection();
                
					Content current = mcurrentWct.Contents[ts.SelectedIndex];
                    
					if (!mmanager.OnContentHiding(current))
					{
						if (ts.TabPages.Count == 1)
						{
							foreach(Content c in mcurrentWct.Contents)
							{
								c.RecordAutoHideRestore();

								cc.Add(c);
							}
                        
							KillDisplayedWindow(mcurrentWct);

							ControlUtilities.Remove(ts.Controls, ts.WindowContentTabbed);

							ControlUtilities.Remove(this.Controls, ts);                    

							ts.Dispose();
						}
						else
						{
							int index = ts.SelectedIndex;

							mcurrentWct.Contents[index].RecordAutoHideRestore();
							
							cc.Add(mcurrentWct.Contents[index]);

							ts.TabPages.RemoveAt(index);
                            
							mcurrentWct.Contents.RemoveAt(index);
						}

						foreach(Content c in cc)
						{
							c.AutoHidden = false;
							c.AutoHidePanel = null;
						}
					}
                    
					mmanager.OnContentHidden(current);
                    
					break;
				}
			}
            
			if (this.Controls.Count == 0)
				this.Hide();
		}
		
		protected void OnPageAutoHide(object sender, EventArgs e)
		{
			UnAutoHideWindowContent(mcurrentWct, false);
		}

		protected void UnAutoHideWindowContent(WindowContentTabbed wct, bool forceKill)
		{
			mmanager.SurpressVisibleEvents += 1;
        
			foreach(TabStub ts in this.Controls)
			{
				if (ts.WindowContentTabbed == wct)
				{
					int count = ts.TabPages.Count;
                    
					for(int i=count-1; i>=0; i--)
					{
						Content c = ts.TabPages[i].Tag as Content;

						c.RecordAutoHideRestore();
					}
                        
					if (forceKill)
						KillDisplayedWindow(wct);
					else
						KillDisplayedWindow(mcurrentWct);

					ControlUtilities.Remove(this.Controls, ts);
                    
					for(int i=count-1; i>=0; i--)
					{
						Content c = ts.TabPages[i].Tag as Content;

						c.AutoHidden = false;
						c.AutoHidePanel = null;
                        
						mmanager.ShowContent(c);
					}
                                        
					break;
				}
			}
            
			if (this.Controls.Count == 0)
				this.Hide();

			mmanager.SurpressVisibleEvents -= 1;
		}

		protected void OnPanelEnter(object sender, EventArgs e)
		{
			mignoreDismiss = true;
		}

		[UseApiElements("User32.SetFocus")]
		protected void OnPanelLeave(object sender, EventArgs e)
		{
			mignoreDismiss = false;

			if (!mkilling && (mcurrentWct != null) && !mcurrentWct.ContainsFocus)
			{
				IntPtr hWnd = User32.GetFocus();
			
				StopDismissTimer();
				StopSlideTimer();

				RemoveDisplayedWindow();
                
				mcurrentWct = null;

				User32.SetFocus(hWnd);
			}	
		}
 
		protected void MonitorPanel(bool add)
		{
			MonitorControl(mcurrentPanel, add);
		}

		protected void MonitorControl(Control c, bool add)
		{
			if (add)
			{
				c.GotFocus += new EventHandler(OnPanelEnter);
				c.LostFocus += new EventHandler(OnPanelLeave);
			}
			else
			{
				c.GotFocus -= new EventHandler(OnPanelEnter);
				c.LostFocus -= new EventHandler(OnPanelLeave);
			}

			foreach(Control child in c.Controls)
				MonitorControl(child, add);
		}
        
		protected override void OnPaintBackground(PaintEventArgs e)
		{
			Color backColor = base.BackColor;

			if (mdefaultColor)
				backColor = ColorUtilities.TabBackgroundFromBaseColor(SystemColors.Control);
			else
				backColor = ColorUtilities.TabBackgroundFromBaseColor(backColor);

			using(SolidBrush brush = new SolidBrush(backColor))
				e.Graphics.FillRectangle(brush, this.ClientRectangle);
		}

    
		protected void OnPageContextMenu(object sender, ContextEventArgs e)
		{
			mmanager.OnShowContextMenu(sender, e);
		}

		[UseApiElements("User32.MoveWindow")]
		protected void OnSlideTick(object sender, EventArgs e)
		{
			if (mslideRunning)
			{            
				if (this.IsDisposed || mcurrentPanel.IsDisposed || mcurrentWct.IsDisposed)
				{
					StopSlideTimer();
					return;
				}

				Rectangle rect = new Rectangle(mcurrentPanel.Left, mcurrentPanel.Top, 
					mcurrentPanel.Width, mcurrentPanel.Height);
    		    
				Size barSize = mcurrentPanel.ResizeBarSize();

				bool lastStep = ((mslideStep+1) >= mslideSteps);

				if (mslideOut)
				{
					switch(this.Dock)
					{
						case DockStyle.Left:
							if (lastStep)
								rect.Width = mslideRect.Width + barSize.Width;
							else
								rect.Width = (mslideRect.Width + barSize.Width) / 
									mslideSteps * (mslideStep + 1);
                            
							mcurrentWct.Location = new Point(rect.Width - mcurrentWct.Width - barSize.Width, 0);
							break;
						case DockStyle.Right:
							int right = mcurrentPanel.Right;
                            
							if (lastStep)
								rect.Width = mslideRect.Width + barSize.Width;
							else
								rect.Width = (mslideRect.Width + barSize.Width) / 
									mslideSteps * (mslideStep + 1);
                                              
							rect.X -= rect.Right - right;
                            
							mcurrentWct.Location = new Point(barSize.Width, 0);
							break;
						case DockStyle.Top:
							if (lastStep)
								rect.Height = mslideRect.Height + barSize.Height;
							else
								rect.Height = (mslideRect.Height + barSize.Height) / 
									mslideSteps * (mslideStep + 1);
                            
							mcurrentWct.Location = new Point(0, rect.Height - mcurrentWct.Height - barSize.Height);
							break;
						case DockStyle.Bottom:
							int bottom = mcurrentPanel.Bottom;
                            
							if (lastStep)
								rect.Height = mslideRect.Height + barSize.Height;
							else
								rect.Height = (mslideRect.Height + barSize.Height) / 
									mslideSteps * (mslideStep + 1);
                                              
							rect.Y -= rect.Bottom - bottom;

							mcurrentWct.Location = new Point(0, barSize.Height);
							break;
					}

					User32.MoveWindow(mcurrentPanel.Handle, rect.Left, rect.Top, rect.Width, rect.Height, true);
                    
					if (lastStep)
					{
						StopSlideTimer();
                        
						if (this.Dock == DockStyle.Top)
						{
							mcurrentPanel.Refresh();
						}
					}
				}
				else
				{
					int steps = mslideSteps - mslideStep;
                    
					switch(this.Dock)
					{
						case DockStyle.Left:
							if (lastStep)
								rect.Width = 0;
							else
								rect.Width = (mslideRect.Width + barSize.Width) / 
									mslideSteps * steps;
							break;
						case DockStyle.Right:
							int right = mcurrentPanel.Right;
                            
							if (lastStep)
								rect.Width = 0;
							else
								rect.Width = (mslideRect.Width + barSize.Width) / 
									mslideSteps * steps;
                                             
							rect.X += right - rect.Right;
							break;
						case DockStyle.Top:
							if (lastStep)
								rect.Height = 0;
							else
								rect.Height = (mslideRect.Height + barSize.Height) / 
									mslideSteps * steps;
							break;
						case DockStyle.Bottom:
							int bottom = mcurrentPanel.Bottom;
                            
							if (lastStep)
								rect.Height = 0;
							else
								rect.Height = (mslideRect.Height + barSize.Height) / 
									mslideSteps * steps;
                                              
							rect.Y += bottom - rect.Bottom;
							break;
					}
                    
					User32.MoveWindow(mcurrentPanel.Handle, rect.Left, rect.Top, rect.Width, rect.Height, true);

					if (lastStep)
					{
						StopSlideTimer();
                        
						RemoveDisplayedWindow();
                        
						mcurrentWct = null;
					}
				}
                
				mslideStep++;
			}
		}

		protected void OnDismissTick(object sender, EventArgs e)
		{
			if (this.IsDisposed || (mcurrentPanel == null) || mcurrentPanel.IsDisposed)
			{
				StopDismissTimer();
				return;
			}

			if (!mignoreDismiss)
			{
				if (mcurrentPanel != null)
				{
					mslideOut = false;
            
					StartSlideTimer();
				}
			}

			StopDismissTimer();
		}
        
		protected void OnContainerResized(object sender, EventArgs e)
		{
			RemoveShowingWindow();
		}

		#endregion

		#region Methods
		
		public void PropogateNameValue(PropogateName name, object value)
		{
			switch(name)
			{
				case PropogateName.BackColor:
					this.BackColor = (Color)value;
					Invalidate();
					break;
				case PropogateName.CaptionFont:
					this.Font = (Font)value;
                    
					int vector = TabStub.TabStubVector(this.Font); 
					this.Size = new Size(vector, vector);
                    
					Invalidate();
					break;
			}
            
			foreach(TabStub ts in Controls)
				ts.PropogateNameValue(name, value);
                
			if (mcurrentPanel != null)
				mcurrentPanel.PropogateNameValue(name, value);
		}

		public bool ContainsContent(Content c)
        {
            return (TabStubForContent(c) != null);
        }

        
        public void BringContentIntoView(Content c)
        {
            foreach(TabStub ts in this.Controls)
            {
                foreach(needle.UI.Controls.Flat.Windows.Forms.TabPage page in ts.TabPages)
                {
                    if (c.Title == (page.Tag as Content).Title)
                    {
                        RemoveShowingWindow();

                        OnPageClicked(ts, new TabStub.TabStubIndexEventArgs(ts.TabPages.IndexOf(page)));                    
                        return;
                    }
                }
            }
        }
                
        public Restore RestoreObjectForContent(Content c)
        {
            StringCollection next = new StringCollection();
            StringCollection previous = new StringCollection();
            StringCollection nextAll = new StringCollection();
            StringCollection previousAll = new StringCollection();

            TabStub marked = TabStubForContent(c);

            bool foundGroup = false;
            
            bool foundContent = false;

            int controlCount = this.Controls.Count;
        
            for(int controlIndex=controlCount-1; controlIndex>=0; controlIndex--)
            {
                TabStub ts = this.Controls[controlIndex] as TabStub;
            
                foreach(needle.UI.Controls.Flat.Windows.Forms.TabPage page in ts.TabPages)
                {
                    Content content = page.Tag as Content;

                    if (marked == ts)
                    {
                        foundGroup = true;

                        if (content.Title == c.Title)
                        {
                            foundContent = true;
                        }
                        else
                        {
                            if (!foundContent)
                                previous.Add(content.Title);
                            else
                                next.Add(content.Title);
                        }
                    }
                    else
                    {
                        if (!foundGroup)
                            previousAll.Add(content.Title);
                        else
                            nextAll.Add(content.Title);                    
                    }
                }
            }

            State windowState = State.DockLeft;
		    
            switch(this.Dock)
            {
                case DockStyle.Left:
                    windowState = State.DockLeft;
                    break;
                case DockStyle.Right:
                    windowState = State.DockRight;
                    break;
                case DockStyle.Top:
                    windowState = State.DockTop;
                    break;
                case DockStyle.Bottom:
                    windowState = State.DockBottom;
                    break;
            }
            
            return new RestoreAutoHideAffinity(null, windowState, c, next, previous, nextAll, previousAll);
        }
        
        public void AddContent(Content content, 
                               StringCollection nex, 
                               StringCollection previous, 
                               StringCollection nextAll, 
                               StringCollection previousAll)
        {
            int nextIndex = 0;
            int previousIndex = 0;
            TabStub nextTabStub = null;
            TabStub previousTabStub = null;
            TabStub nextAllTabStub = null;
            TabStub previousAllTabStub = null;
        
            int controlCount = this.Controls.Count;
        
            for(int controlIndex=controlCount-1; controlIndex>=0; controlIndex--)
            {
                TabStub ts = this.Controls[controlIndex] as TabStub;

                foreach(needle.UI.Controls.Flat.Windows.Forms.TabPage page in ts.TabPages)
                {
                    Content c = page.Tag as Content;

                    if (previous.Contains(c.Title))
                    {
                        previousIndex = ts.TabPages.IndexOf(page);
                        previousTabStub = ts;
                    }
                    
                    if (nex.Contains(c.Title))
                    {
                        if (nextTabStub == null)
                        {
                            nextIndex = ts.TabPages.IndexOf(page);
                            nextTabStub = ts;
                        }
                    }

                    if (previousAll.Contains(c.Title))
                        previousAllTabStub = ts;

                    if (nextAll.Contains(c.Title))
                    {
                        if (nextAllTabStub == null)
                            nextAllTabStub = ts;
                    }
                }
            }            

            if ((previousTabStub == null) && (nextTabStub == null))
            {
                int insertIndex = Controls.Count;
            
                if (previousAllTabStub != null)
                    insertIndex = Controls.IndexOf(previousAllTabStub);
                else
                {
                    if (nextAllTabStub != null)
                        insertIndex = Controls.IndexOf(nextAllTabStub) + 1;
                }
            
                ContentCollection cs = new ContentCollection();
                
                cs.Add(content);
            
                AddContentsAsGroup(cs, insertIndex);
            }
            else
            {
                if (previousTabStub != null)
                    AddContentIntoTabStub(content, previousTabStub, previousIndex + 1);
                else
                    AddContentIntoTabStub(content, nextTabStub, nextIndex);
            }
        }

        public void AddContentIntoTabStub(Content content, TabStub ts, int index)
        {
            if ((mcurrentWct != null) && (mcurrentWct == ts.WindowContentTabbed))
            {
                RemoveDisplayedWindow();
            }                
        
            needle.UI.Controls.Flat.Windows.Forms.TabPage page = new needle.UI.Controls.Flat.Windows.Forms.TabPage();
		        
            page.Title = content.Title;
            page.ImageList = content.ImageList;
            page.ImageIndex = content.ImageIndex;
			page.Icon = content.Icon;
                
            page.Tag = content;
		        
            ts.TabPages.Insert(index, page);
		        
            content.AutoHidePanel = this;
            content.AutoHidden = true;
        
            ts.WindowContentTabbed.Contents.Insert(index, content);

            if (!this.Visible)
                this.Show();
                
            Invalidate();
        }
        
        public void AddContentsAsGroup(ContentCollection contents)
        {
            AddContentsAsGroup(contents, 0);
        }
            
        public void AddContentsAsGroup(ContentCollection contents, int index)
		{
            TabStub ts = new TabStub();

            ts.Font = mmanager.CaptionFont;
            ts.BackColor = mmanager.BackColor;
            ts.ForeColor = mmanager.InactiveTextColor;

            ts.PageOver += new TabStub.TabStubIndexEventHandler(OnPageOver);
            ts.PageClicked += new TabStub.TabStubIndexEventHandler(OnPageClicked);
            ts.PagesLeave += new TabStub.TabStubEventHandler(OnPagesLeave);
		    
            foreach(Content c in contents)
            {
                needle.UI.Controls.Flat.Windows.Forms.TabPage page = new needle.UI.Controls.Flat.Windows.Forms.TabPage();
		        
                page.Title = c.Title;
                page.ImageList = c.ImageList;
                page.ImageIndex = c.ImageIndex;
				page.Icon = c.Icon;
                
                page.Tag = c;
		        
                ts.TabPages.Add(page);
		        
                c.AutoHidePanel = this;
                c.AutoHidden = true;
            }

            State windowState = State.DockLeft;
		    
            switch(this.Dock)
            {
                case DockStyle.Left:
                    windowState = State.DockLeft;
                    ts.Edging = Edge.Left;
                    ts.Dock = DockStyle.Top;
                    break;
                case DockStyle.Right:
                    windowState = State.DockRight;
                    ts.Edging = Edge.Right;
                    ts.Dock = DockStyle.Top;
                    break;
                case DockStyle.Top:
                    windowState = State.DockTop;
                    ts.Edging = Edge.Top;
                    ts.Dock = DockStyle.Left;
                    break;
                case DockStyle.Bottom:
                    windowState = State.DockBottom;
                    ts.Edging = Edge.Bottom;
                    ts.Dock = DockStyle.Left;
                    break;
            }
		    
            Controls.Add(ts);
            
            Controls.SetChildIndex(ts, index);
		    
            WindowContentTabbed wct = mmanager.CreateWindowForContent(null, new EventHandler(OnPageClose),
                                                                      null, new EventHandler(OnPageAutoHide),
                                                                      new ContextEventHandler(OnPageContextMenu)) as WindowContentTabbed;
            
            foreach(Content c in contents)
                wct.Contents.Add(c);
                
            wct.Size = contents[0].AutoHideSize;

            wct.State = windowState;

            wct.RedockAllowed = false;

            wct.TabControl.HideTabsMode = needle.UI.Controls.Flat.Windows.Forms.TabControl.HideTabsModes.HideAlways;

            ts.WindowContentTabbed = wct;
            
            if (!this.Visible)
			    this.Show();
			    
	        Invalidate();
		}

		public void InvertAutoHideWindowContent(WindowContentTabbed wct)
		{
			UnAutoHideWindowContent(wct, true);
		}
        
        public void RemoveContent(Content c)
        {
            TabStub targetTS = null;
            needle.UI.Controls.Flat.Windows.Forms.TabPage targetPage = null;
        
            foreach(TabStub ts in this.Controls)
            {
                foreach(needle.UI.Controls.Flat.Windows.Forms.TabPage page in ts.TabPages)
                {
                    Content pageC = page.Tag as Content;
                    
                    if (pageC == c)
                    {
                        targetTS = ts;
                        targetPage = page;
                        break;
                    }
                }
            }            
            
            if ((targetTS != null) && (targetPage != null))
            {
                if (targetTS.TabPages.Count == 1)
                {
                    int count = targetTS.WindowContentTabbed.Contents.Count;
                    
                    for(int i=0; i<count; i++)
                        targetTS.WindowContentTabbed.Contents.RemoveAt(0);

                    if (targetTS.WindowContentTabbed == mcurrentWct)
                    {
                        KillDisplayedWindow(mcurrentWct);
                    }
                                        
                    ControlUtilities.Remove(targetTS.Controls, targetTS.WindowContentTabbed);

                    ControlUtilities.Remove(this.Controls, targetTS);
                    
                    targetTS.Dispose();                    
                }
                else
                {
                    if (targetTS.WindowContentTabbed == mcurrentWct)
                    {
                        bool found = false;
                    
                        foreach(Content cWCT in mcurrentWct.Contents)
                        {
                            if (cWCT == c)
                            {
                                found = true;                     
                                break;
                            }
                        }
                        
                        if (found)
                        {
                            int index = mcurrentWct.Contents.IndexOf(c);
                        
                            targetTS.TabPages.RemoveAt(index);
                        
                            mcurrentWct.Contents.RemoveAt(index);
                        }
                    }
                
                    targetTS.TabPages.Remove(targetPage);
                }

                c.AutoHidePanel = null;
            }

            if (this.Controls.Count == 0)
                this.Hide();
        }
        
        [UseApiElements("User32.GetFocus, User32.SetFocus")]
		public void RemoveShowingWindow()
        {
            mignoreDismiss = false;

            if (mcurrentWct != null)
            {
                IntPtr hWnd = User32.GetFocus();

                StopDismissTimer();
                StopSlideTimer();
			
                RemoveDisplayedWindow();
                
                mcurrentWct = null;

                User32.SetFocus(hWnd);
            }	
            
            Invalidate();
        }
        
        [UseApiElements("User32.ClientToScreen")]
		public bool PreFilterMessage(ref Message msg)
        {
            Form parentForm = this.FindForm();

            if ((parentForm != null) && (parentForm == Form.ActiveForm) && 
                parentForm.ContainsFocus && (mcurrentPanel != null) && 
                !mcurrentPanel.IsDisposed)
            {		
                switch(msg.Msg)
                {
                    case (int)Msgs.WM_MOUSEMOVE:
                        POINT screenPos;
                        screenPos.x = (int)((uint)msg.LParam & 0x0000FFFFU);
                        screenPos.y = (int)(((uint)msg.LParam & 0xFFFF0000U) >> 16);

                        User32.ClientToScreen(msg.HWnd, ref screenPos);

                        Rectangle panelRect = mcurrentPanel.RectangleToScreen(mcurrentPanel.ClientRectangle);
                        Rectangle thisRect = this.RectangleToScreen(this.ClientRectangle);

                        if (mdismissRunning)
                        {
                            if (panelRect.Contains(new Point(screenPos.x, screenPos.y)))
                            {
                                StopDismissTimer();
                           }
                        }
                        else
                        {
                            if (!panelRect.Contains(new Point(screenPos.x, screenPos.y)) &&
                                !thisRect.Contains(new Point(screenPos.x, screenPos.y)))
                            {
                                OnPagesLeave(null, EventArgs.Empty);
                            }
                        }

                        break;
                }
            }

            return false;
		}

		#endregion

		#region Properties

		public override Color BackColor
		{
			get { return base.BackColor; }

			set
			{
				if (this.BackColor != value)
				{
					mdefaultColor = (value == SystemColors.Control);
					base.BackColor = value;
					Invalidate();
				}
			}
		}

		#endregion
    }
}
